/**
* (c) 2013 - 2014 dmulloy2
*/
package net.t7seven7t.swornguard.handlers;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Filter;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import lombok.AllArgsConstructor;
import net.dmulloy2.types.Reloadable;
import net.dmulloy2.util.FormatUtil;
import net.dmulloy2.util.Util;
import net.t7seven7t.swornguard.SwornGuard;
import net.t7seven7t.swornguard.events.CheatEvent;
import net.t7seven7t.swornguard.types.CheatType;
import net.t7seven7t.swornguard.types.Permission;
import net.t7seven7t.swornguard.types.PlayerData;
import net.t7seven7t.swornguard.types.Preconditions;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.message.Message;
import org.bukkit.entity.Player;
/**
* @author dmulloy2
*/
public class LogFilterHandler implements Filter, org.apache.logging.log4j.core.Filter, Reloadable {
private final SwornGuard plugin;
private final Preconditions preconditions;
private boolean speedDetectorEnabled;
private List<Pattern> logFilters;
public LogFilterHandler(SwornGuard plugin) {
this.plugin = plugin;
this.preconditions = plugin.getPreconditions();
this.reload();
}
private final boolean filter(String message) {
if (message == null) {
plugin.getLogHandler().log(Level.WARNING, "Encountered a null message!");
return true; // Probably bukkit's piss-poor way of handling command exceptions
}
// Do internal checks first
if (message.contains("moved too quickly!")) {
String playerName = message.split(" ")[0];
Player player = Util.matchPlayer(playerName);
if (player != null) {
if (speedDetectorEnabled) {
if (! plugin.getPermissionHandler().hasPermission(player, Permission.ALLOW_FLY)) {
if (! player.getAllowFlight() && ! player.isInsideVehicle()) {
if (! preconditions.isPlayerFallingIntoVoid(player) && ! preconditions.isPlayerInsideCar(player)
&& ! preconditions.isNewPlayerJoin(player) && ! preconditions.hasRecentlyTeleported(player)) {
PlayerData data = plugin.getPlayerDataCache().getData(player);
data.setConsecutivePings(data.getConsecutivePings() + 1);
if (data.getConsecutivePings() >= 2) {
// Announce the cheat
CheatEvent event = new CheatEvent(player, CheatType.SPEED,
FormatUtil.format(plugin.getMessage("cheat_message"), player.getName(), "moving too quickly!"));
plugin.getCheatHandler().announceCheat(event);
// Reset their consecutive pings
data.setConsecutivePings(0);
}
}
}
}
}
return false;
}
}
// Now filter messages defined in the config
if (! logFilters.isEmpty()) {
for (Pattern filter : logFilters) {
if (filter.matcher(message).matches()) {
return false;
}
}
}
return true;
}
private final void applyFilters() {
java.util.logging.Logger logger = plugin.getServer().getLogger();
Filter current = logger.getFilter();
if (current == null || current instanceof LogFilterHandler) {
logger.setFilter(this);
} else {
logger.setFilter(new FilterDelegate(current, this));
}
((Logger) LogManager.getRootLogger()).addFilter(this);
}
@AllArgsConstructor
private class FilterDelegate implements Filter {
private final Filter original;
private final Filter ours;
@Override
public boolean isLoggable(LogRecord record) {
if (! original.isLoggable(record)) {
return false;
}
return ours.isLoggable(record);
}
}
@Override
public void reload() {
this.speedDetectorEnabled = plugin.getConfig().getBoolean("speedDetectorEnabled", true);
this.logFilters = new ArrayList<Pattern>();
if (plugin.getConfig().isSet("log-filters")) {
for (String string : plugin.getConfig().getStringList("log-filters")) {
try {
logFilters.add(Pattern.compile(string));
} catch (PatternSyntaxException ex) {
plugin.getLogHandler().log(Level.WARNING, "Supplied regex filter \"{0}\" is invalid!", string);
}
}
}
if (speedDetectorEnabled && ! logFilters.isEmpty()) {
this.applyFilters();
}
}
// Default Filter Method
@Override
public boolean isLoggable(LogRecord record) {
return filter(record.getMessage());
}
// ---- Log4J Filter Methods ---- //
@Override
public Result filter(LogEvent event) {
return filter(event.getMessage().getFormattedMessage()) ? Result.ACCEPT : Result.DENY;
}
@Override
public Result filter(Logger logger, org.apache.logging.log4j.Level level, Marker marker, String message, Object... args) {
return filter(message) ? Result.ACCEPT : Result.DENY;
}
@Override
public Result filter(Logger logger, org.apache.logging.log4j.Level level, Marker marker, Object message, Throwable ex) {
return filter(message.toString()) ? Result.ACCEPT : Result.DENY;
}
@Override
public Result filter(Logger logger, org.apache.logging.log4j.Level level, Marker marker, Message message, Throwable ex) {
return filter(message.getFormattedMessage()) ? Result.ACCEPT : Result.DENY;
}
@Override
public Result getOnMatch() {
return Result.NEUTRAL;
}
@Override
public Result getOnMismatch() {
return Result.NEUTRAL;
}
}